#pragma once
#include <iostream>
#include <vector>
#include <string>
#include <unordered_map>
#include "Log.hpp"
#include "Epoller.hpp"
#include "Connection.hpp"
using namespace std;
using namespace EpollerModule;
const int maxevents = 64;
#define EPOLL_BLOCK  -1


class Reactor {
public :
    Reactor() 
        :_epoller(new Epoller())
        ,_isrunning(false)
        ,_timeout(EPOLL_BLOCK)
    {
        _epoller->InitEpoller();
    }

    bool ConnectionExist(int sockfd) {
        auto it = _connections.find(sockfd);
        if (it == _connections.end()) {
            return false;
        }
        return true;
    }

    void AddConnection(Connection* conn) {
        if (conn == nullptr) {
            return;
        }
        if (ConnectionExist(conn->SockFd())) {
            return;
        }
        _connections[conn->SockFd()] = conn;
        //将关心的文件描述符添加到_epoller中
        _epoller->AddEvent(conn->SockFd(), conn->Events());
    }

    void DelConnection(Connection* conn) {
        if (!ConnectionExist(conn->SockFd())) {
            return ;
        }
        // 先从底层_epoller中移除事件
        _epoller->DelEvent(conn->SockFd());
        // 再从_connections中移除
        _connections.erase(conn->SockFd());
        // 再关闭文件描述符
        close(conn->SockFd());
        // 最后在删除conn
        delete conn;
    
    }

    void SetWriteRead(Connection* conn, bool isread, bool iswrite) {
        uint32_t events = EPOLLET;
        if (isread) {
            events |= EPOLLIN;
        }
        if (iswrite) {
            events |= EPOLLOUT;
        }
        conn->SetEvents(events);
        // 将关心事件同步到_epoller中
        _epoller->ModEvent(conn->SockFd(), events);
    }

    void Dispatch() {
        _isrunning = true;
        while (_isrunning) {
            int n = _epoller->Wait(_revs, maxevents, _timeout);
            if (n > 0) {
                PrintDebug();
                lg.LogMessage(Info, "有新的就绪事件到来, 当前的就绪事件个数是: %d", n);
                for (int i = 0; i < n; i++) {
                    uint32_t events = _revs[i].events;
                    int sockfd = _revs[i].data.fd;
                    if (events & EPOLLERR) {
                        events |= EPOLLIN | EPOLLOUT;
                    }
                    if (events & EPOLLHUP) {
                        events |= EPOLLIN | EPOLLOUT;
                    }
                    if (events & EPOLLIN && ConnectionExist(sockfd)) {
                        if (_connections[sockfd]->_recver) {
                            _connections[sockfd]->_recver(_connections[sockfd]);
                        }
                    }
                    if (events & EPOLLOUT && ConnectionExist(sockfd)) {
                        if (_connections[sockfd]->_sender) {
                            _connections[sockfd]->_sender(_connections[sockfd]);
                        }
                        
                    }
                }

            } else if (n == 0) {
                continue;
            } else {
                lg.LogMessage(Error, "epoller wait error, errno: %d, error string: %s", errno, strerror(errno));
                break;
            }
        }
        _isrunning = false;
    }

    void PrintDebug() {
        cout << "current sockfd list: ";
        for (auto& p : _connections) {
            cout << p.first << " ";
        }
        cout << endl;
    }
    ~Reactor() {

    }

private :
    unordered_map<int, Connection*> _connections;
    Epoller* _epoller;
    struct epoll_event _revs[maxevents];
    bool _isrunning;
    int _timeout;
};